﻿using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using LogikBug.Async.Tasks;

namespace LogikBug.Async.ConsoleApp
{
	class Program
	{
		private static int _counter;
		private static int _total = 10000;
		private static Stopwatch _stopwatch = new Stopwatch();
		private static readonly AgentSettings Settings = new AgentSettings(true, 200, TimeSpan.FromSeconds(1.0d).TotalSeconds / 60);
		private static readonly AgentController Controller = new AgentController(Settings, new ControllerEventHandler());
		private static readonly TimedAgentController TimedController = new TimedAgentController(Settings);
		
		// System.Threading.Tasks Tests
		static void Main(string[] args)
		{
			string line;
			while ((line = Console.ReadLine()) != "q")
			{
				_stopwatch.Reset();

				if (line == "agent add")
				{
					for (int i = 0; i < _total; i++)
					{
						Controller.Add(new ActionAgent<int>
							
							(i, Callback));
					}

					_stopwatch.Start();
					Controller.Run();
				}
				else if (line == "agent activate")
				{
					_stopwatch.Start();

					for (int i = 0; i < _total; i++)
					{
						Controller.Activate(new ActionAgent<int>(i, Callback));
					}
				}
				else if (line == "task")
				{
					_stopwatch.Start();

					for (int i = 0; i < _total; i++)
					{
						//Task.Factory.StartNew(TaskCallback).ContinueWith(TaskContinueWith);
						Task.Factory.StartNew(TaskCallback, i).ContinueWith(TaskContinueWith);
					}
				}
			}
		}

		private static void TimedCallback(DateTime lastUpdate)
		{
			TimedController.Activate(new ActionAgent<DateTime>(lastUpdate, Callback));
		}

		private static void Callback()
		{
			Interlocked.Increment(ref _counter);
		}

		private static void Callback(int i)
		{
			Callback();
			WriteLine(i);
		}

		private static void Callback(DateTime dateTime)
		{
			Callback();
			WriteLine(dateTime);
		}

		private static void WriteLine(object obj)
		{
			Console.WriteLine(obj);
		}

		private static void TaskCallback()
		{
			Callback();
		}

		private static void TaskCallback(object i)
		{
			Callback();
			WriteLine(i);
		}

		private static void TaskContinueWith(Task task)
		{
			if (_counter == _total)
			{
				ThreadsComplete();
			}
		}

		private static void ThreadsComplete()
		{
			_stopwatch.Stop();
			Console.WriteLine("Agents Executed: {0} \tElapsed Time: {1}", Interlocked.Exchange(ref _counter, 0), _stopwatch.Elapsed.TotalSeconds);
		}

		private class ControllerEventHandler : IAgentControllerEventHandler
		{
			int previouscount;

			public void AgentStarted(AgentController controller, AgentContext context)
			{
			}

			public void AgentErrored(AgentController controller, AgentContext context, AgentResult result, Exception exception)
			{
			}

			public void AgentCompleted(AgentController controller, AgentContext context, AgentResult result)
			{
				int count = controller.AgentContextCount;

				if (controller.AgentQueueCount == 0 && count == 0)
				{
					ThreadsComplete();
				}
				else
				{
					//if (count != previouscount)
					//{
					//    previouscount = count;

					//    Console.WriteLine("AgentQueue: {0} AgentContexts: {1}", controller.AgentQueueCount, previouscount);
					//}
				}
			}

			public void AgentDisposing(AgentController controller, AgentContext context, AgentResult result)
			{
			}
		}
	}
}
